home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The PC-SIG Library 9
/
The PC-SIG Library on CD ROM - Ninth Edition.iso
/
001_100
/
DISK0041
/
DISK0041.ZIP
/
MSYIBM.ASM
< prev
next >
Wrap
Assembly Source File
|
1984-12-08
|
31KB
|
1,181 lines
title term
; edit history
; Fixed destructive tab problem (received from many people)
; Fixed insert/delete line problem when at bottom/top of screen.
; Newlines never scroll in inverse video lines
; Implemented cursor save/restore (from Univ. Md.)
; "Echo" status on mode corrected.
; JD, 6 December 1984
public term, gss ; entry points
include msdefs.h
; some character definitions
chesc equ 27
bel equ 7
print_out equ 05h ; dos function to print to printer
pbout equ 02h ; dos function to print a character
prscan equ 72h ; print-screen scan code...
upscan equ 49h ; up page
dnscan equ 51h ; down page
ctlup equ 84h ; ctl-up page
ctldn equ 76h ; ctl-down page
homscn equ 47h ; home screen
endscn equ 4fh ; end of screen
screen equ 10h ; bios screen call
kb equ 16h ; keyboard interrupt
alt_shift equ 8H ; alt shift key down
ctl_shift equ 4H ; ctl key down
left_shift equ 2H ; left shift key down
right_shift equ 1H ; right shift key down
timer equ 40h ; timer port
bel_prt equ 61h ; speaker control
crt_status equ 3dah ; crt status port
disp_enb equ 8 ; display enable bit
uparr equ 48h ; scan codes for arrow keys
dnarr equ 50h
lftarr equ 4bh
rgtarr equ 4dh
modfrm struc ; format of mode line
db 'Esc chr: '
m_echr db 2 dup (?)
db ', Port: '
m_prt db 1 dup (?)
db ', Speed: '
m_baud db 4 dup (?)
db ', Parity: '
m_par db 4 dup (?)
db ', Echo: '
m_echo db 3 dup (?)
db ', Type '
m_hlp db 2 dup (?)
db '? for Help'
modfrm ends
datas segment public 'datas'
waste db 100h dup (?) ;*** need this junk because assembler
;*** generates non-relocatable offsets
;*** for things like
;*** "sub di,offset foo"
;*** if offset foo < 100H
; stuff for screen routines
flags db ? ; status flags...
flags1 db 0 ; internal flags.
prtscr equ 80h ; print screen pressed
lnwrap equ 40h ; line wrap enabled.
inited equ 08h ; been here before...
cursor dw ?
esc_ch db ?
argadr dw ? ; address of arg blk
ckeys db 0,prscan,dnscan,upscan,endscn,homscn,ctlup,ctldn
db uparr,dnarr,lftarr,rgtarr
lckeys equ $-ckeys
; ckacts must parallel ckeys above...
ckacts dw trnbrk,trnprs,upwpg,dnwpg,endwnd,homwnd,dnwind,upwind
dw trnupw,trndnw,trnlfw,trnrgw
uptrn db esc,'A'
dntrn db esc,'B'
rgtrn db esc,'C'
lftrn db esc,'D'
spctab db chesc,cr,lf,bs,tab,bel
lspctab equ $-spctab
spcjmp dw outesc,outcr,outlf,outbs,outtab,outbel ; must match spctab
esctab db 'YABCDEFGHIJKLM'
db 'NOZ@[pq<vw'
db 'jk'
lesctab equ $-esctab
; escjmp must parallel esctab above
escjmp dw movcur,curup,curdwn,currt,outbs,clrscr,outign,outign,curhom
dw revind,clreow,clreol,inslin,dellin,delchr,noins
dw vtident,entins,doansi
dw invvid,nrmvid,outign,dowrap,nowrap
dw savecur,restcur
vtidstr db chesc,'/K'
lvtidst equ $-vtidstr
coord dw ?
insmod db ?
wcoord dw ?
ttstate dw outtt0
curattr db ? ; current attribute
ansarg db ? ; ansi argument value
igncnt db ? ; # of chars to ignore
beldiv dw 2dch ; 550 hz?
crt_mode db ?
crt_cols db ?
crt_lins db ?
low_rgt dw ? ; lower right corner of window
; key redefinitions
ktrntab dw ? ; address of translation table
krpltab dw ? ; address of replacement table
tmptab db 0eh,3bh ; scan code for bs, f1
ktlen dw ?
modbuf modfrm <> ; mode line buffer
; routine to call for captured output
captrtn dw ?
oldcur dw 0 ; save'd cursor position
; some static data for mode line
unkbaud db 'Unk ' ; must be 4 chars...
baudn db '45.5'
db ' 50'
db ' 75'
db ' 110'
db ' 135'
db ' 150'
db ' 300'
db ' 600'
db '1200'
db '1800'
db '2000'
db '2400'
db '4800'
db '9600'
baudnsiz equ 14 ; # of baud rates known (tbl size / 4)
parnams db 'Even'
db 'Mark'
db 'None'
db 'Odd ' ; must be 4 chars
db 'Spc '
offmsg db 'Off'
onmsg db 'On '
lclmsg db 'Lcl'
remmsg db 'Rem'
; storage for multi-window stuff
swidth equ 80
slen equ 24
npgs equ 5 ; # of pages on each side
bsize equ swidth*slen*npgs*2
scrsav dw swidth*slen dup (0700H) ; a blank screen
; circular buffer. To work properly, the buffer size should be an exact
; multiple of swidth*2
cbuf struc
pp dw ? ; place ptr in buffer
bend dw ? ; end of buffer
orig dw ? ; buffer origin
lcnt dw 0 ; # of lines in buffer.
cbuf ends
topbuf db bsize dup (?)
botbuf db bsize dup (?) ; top and bottom windows
tlbuf db swidth*2 dup (?)
blbuf db swidth*2 dup (?)
twnd cbuf <topbuf,topbuf+bsize-1,topbuf,0>
bwnd cbuf <botbuf,botbuf+bsize-1,botbuf,0>
portno db ?
prton db 'Printer: on'
prtnlen equ $-prton
prtoff db 'Printer: off'
prtflen equ $-prtoff
datas ends
code segment public ; code segment
extrn prtchr:near,outchr:near,sendbr:near
assume cs:code,ds:datas,es:datas
scrini proc near ; init screen stuff
mov ah,15 ; read video state...
int screen
mov crt_mode,al ; save crt mode
cmp ah,crt_cols ; is real # of cols < passed?
jge scrin1 ; no
mov crt_cols,ah ; yes, save # of cols
scrin1: mov dl,crt_cols ; # of cols again
mov dh,crt_lins ; and # of rows
dec dl
dec dh
mov low_rgt,dx ; save away window address
mov insmod,0 ; not in insert mode
mov dx,cursor ; assume old cursor
test flags1,inited ; have we been here before?
jnz scrin4 ; yes, use old cursor
mov curattr,07 ; else set nice screen attribute
mov ttstate,offset outtt0 ; normal screen state
mov ah,3 ; figure out where cursor is
xor bh,bh ; page 0
int screen ; read cursor position
cmp dh,crt_lins ; past logical end of screen?
jb scrin2 ; no, keep going
mov dh,byte ptr low_rgt+1 ; yes, just use lower right corner
scrin2: cmp dl,crt_cols ; maybe past right margin
jb scrin3 ; no, use the way it is
mov dl,byte ptr low_rgt
scrin3: mov cursor,dx ; init cursor
scrin4: mov ah,2
xor bh,bh
int screen ; set cursor in case it moved
ret
scrini endp
argini proc near ; read passed arguments
mov bx,argadr ; base of argument block
mov al,[bx].flgs ; get flags
and al,capt+emheath+havtt+trnctl+lclecho+modoff
mov flags,al ; mask for allowable and save
and flags1,not (prtscr) ; these are allowable
; (others remain).
mov al,[bx].prt
cmp al,portno ; using same port?
je argin1 ; yes, go on
and flags1,not inited ; else re-init stuff
argin1: mov portno,al ; update port number
mov al,[bx].cols
mov crt_cols,al
mov al,[bx].rows
mov crt_lins,al ; init # of rows and cols
mov ax,[bx].captr
mov captrtn,ax ; buffer capture routine
mov ax,[bx].belld
mov beldiv,ax ; bell divisor
mov ax,[bx].klen
mov ktlen,ax ; length of key redef tbl
mov ax,[bx].ktab
mov ktrntab,ax ; save key translation table
mov ax,[bx].krpl
mov krpltab,ax
mov al,[bx].escc
mov esc_ch,al
ret ; that's it
argini endp
modlin proc near ; turn on mode line
mov al,esc_ch
mov modbuf.m_echr,' ' ; first char is initial space
mov modbuf.m_hlp,' ' ; goes here too.
cmp al,32 ; printable?
jnb modl1 ; yes, keep going
add al,40h ; made printable
mov modbuf.m_echr,'^' ; note control char
mov modbuf.m_hlp,'^'
modl1: mov modbuf.m_echr+1,al ; fill in character
mov modbuf.m_hlp+1,al
mov bx,argadr ; get argument block
mov al,[bx].baudb ; get baud bits
mov si,offset unkbaud ; assume unknown baud
cmp al,baudnsiz ; too big?
jnb modl2 ; yes, use default
mov cl,2 ; each is 4 bytes long
shl al,cl
mov ah,0
add ax,offset baudn
mov si,ax
modl2: mov cx,size m_baud ; length of baud space
mov di,offset modbuf.m_baud
rep movsb ; copy in baud rate
mov al,[bx].parity ; get parity code
mov cl,2 ; each is 4 bytes long...
shl al,cl
mov ah,0
add ax,offset parnams ; names of parity settings
mov si,ax
mov cx,4 ; each is 4 long
mov di,offset modbuf.m_par
rep movsb
mov si,offset remmsg ; Assume remote echoing.
test flags,lclecho ; Is remote side echoing?
jz modl4 ; Yes, keep going
mov si,offset lclmsg ; Else it's local echoing.
modl4: mov cx,3 ; size of on/off
mov di,offset modbuf.m_echo
rep movsb
mov al,'1'
cmp portno,1 ; port 1?
je modl5 ; yes, keep going
mov al,'2'
modl5: mov modbuf.m_prt,al ; fill in port number
mov cx,size modfrm ; this is size of mode line
mov si,offset modbuf ; mode line image
; alternate entry to write an alternate mode line
modwrt: push cx
push si ; save mode line and size
mov dx,24 * 100h ; 25th line for mode line
push word ptr curattr ; save current attributes
mov curattr,70h ; want inverse video
call clreol ; clear to end of line...
pop word ptr curattr ; restore attributes
mov dx,24 * 100h
mov bh,0
mov ah,2 ; set cursor position
int screen
pop si
pop cx ; restore these
modl6: lodsb ; get a byte
mov ah,14 ; write to terminal
mov bh,0 ; page 0
int screen
loop modl6 ; write out entire mode line
mov dx,cursor
mov ah,2
mov bh,0
int screen ; put cursor back where it belongs
ret ; and return
modlin endp
clrmod proc near ; clear mode line
mov ax,600h ; blank window
mov cx,24 * 100h ; beginning of window
mov dx,24 * 100h + 79 ; end of window
mov bh,07 ; nice attribute
int screen ; clear mode line
ret ; and return
clrmod endp
term proc near ; terminal emulator entry point
mov argadr,ax ; save argument ptr
push es ; save caller's extra segment address
mov ax,seg datas
mov es,ax
call argini ; init options from arg address
call scrini ; init screen stuff
test flags1,inited ; have we run yet?
jz term1 ; no, forget this part
call restscr ; restore screen
term1: or flags1,inited ; remember we've run already.
call clrmod ; empty mode line
test flags,modoff ; is mode line disabled?
jnz lp ; yes, skip it
call modlin ; turn on mode line
lp: call portchr ; char at port?
jnc chkinp ; no, keep going
call outtty ; print on terminal
chkinp: mov ah,1
int kb
jz lp ; nothing available...
xor ah,ah
int kb ; get the char from the buffer
push ax ; save character temporarily
call gss ; get shift state into al
mov bl,al ; save shift state
pop ax
cmp al,esc_ch ; escape character?
je quit ; yes, stop here
call trnout ; translate if nec., output to prt
jmp chkinp ; and keep going
quit: call clrmod ; erase mode line
call savescr ; save screen
mov al,flags
mov bx,argadr
mov [bx].flgs,al ; update flags in arg block
pop es ; restore segment register
ret ; and return to caller
term endp
; get shift state into al. We only care about shift, ctl, and alt keys.
; right shift is collapsed into left shift.
gss proc near
mov ah,2
int kb ; get current shift state
mov bl,al ; copy for a moment
and bl,right_shift ; mask out all but right shift
shl bl,1 ; move right shift to left shift pos
or al,bl ; collapse shift bits
and al,(left_shift + alt_shift + ctl_shift)
ret
gss endp
; save the screen so we can restore it
; maybe save cursor also.
savescr proc near
push ds
mov si,0
mov di,offset scrsav ; place to put screen
mov cx,80*24 ; # of words on screen
call scrseg
push ax ; save screen segment
call scrwait ; wait for screen to be ready
pop ds ; address screen
rep movsw ; save the screen
pop ds ; restore this
ret ; and return
savescr endp
; restore screen from scrsav buffer
restscr proc near
push es
mov si,offset scrsav ; source
mov di,0
mov cx,80*24
call scrseg
mov es,ax
call scrwait
rep movsw ; restore it
pop es
ret
restscr endp
; send the character in al out to the serial port
; handle echoing also...
outprt proc near
test flags,lclecho ; echoing?
jz outpr1 ; no, forget it
push ax ; save char
call outtty ; print it
pop ax ; restore
outpr1: mov ah,al ; this is where outchr expects it
call outchr ; output to the port
nop
nop
nop ; skip returns...
ret
outprt endp
; returns with carry on if a character is available
portchr proc near
call prtchr ; character at port?
jmp short portc1 ; yes, go handle
nop ; skip return is stupid...
clc ; no carry -> no character
ret ; and return...
portc1: and al,7fh ; we don't worry about parity here
stc ; have a character
ret ; and return
portchr endp
; translate the scan code in ah according to the translate table
; given in ktrntab/krpltab, output to port. If no translation,
; use ascii char in al. (should probably include shift state
; somewhere). Shift state is in bl.
trnout proc near
test flags,havtt ; translate table given?
jz trnou3 ; no, just output character
push ax ; save original value
mov al,ah ; put scan code into ah
mov ah,bl ; shift state into top half.
mov di,ktrntab ; pick up translate tbl
mov cx,ktlen ; length of tbl
repne scasw ; look for our key
pop ax ; recover character
jne trnou3 ; not found, forget it
sub di,ktrntab ; get index into tbl
sub di,2 ; (minus 2 for pre-increment)
mov bx,krpltab ; get replacement table
mov si,[bx][di] ; and addr of replacement
mov cl,[si] ; get first byte (length)
xor ch,ch ; clear high-order byte
inc si ; point to translation string
trnou2: lodsb ; get a byte
push si
push cx ; save important registers
call outprt ; send to port
pop cx
pop si
loop trnou2 ; send all chars
ret ; and return
trnou3: cmp ah,4eh ;*** plus key thing?
je trnmod ; yes, go toggle mode line
cmp al,0 ; is it a special code?
jne trnou4 ; no, don't do this
mov al,ah ; get scan code
mov cx,lckeys ; length of table
mov di,offset ckeys ; table address
repne scasb
mov al,0 ; ascii code was 0...
jne trnou4 ; not found, keep going
sub di,offset ckeys+1 ; get table offset
shl di,1 ; shift for word offset
jmp ckacts[di] ; jump to appropriate routine
trnou4: call outprt ; just output single char
ret ; and return
trnmod: test flags,modoff ; mode line already off?
jnz trnm1 ; yes, go turn on
call clrmod ; no, clear mode line here
or flags,modoff ; turn on flag
ret ; and return
trnm1: call modlin ; turn on mode line
and flags,not modoff ; clear flag
ret ; and return
trnbrk: mov ah,dconio
mov dl,0ffH
int dos ; read the bogus ^C DOS gets.
call sendbr
ret
trnprs: xor flags1,prtscr ; flip the flag
and flags,not modoff ; turn on mode line
mov si,offset prton
mov cx,prtnlen
test flags1,prtscr ; did it go on?
jnz trnpr1 ; yes, say so
mov si,offset prtoff
mov cx,prtflen
trnpr1: call modwrt ; write into mode line
ret ; and return
; common entry for arrow keys
trnarr: mov cx,2 ; length is always 2
jmp trnou2 ; go send definition
trnupw: mov si,offset uptrn
jmp trnarr
trndnw: mov si,offset dntrn
jmp trnarr
trnlfw: mov si,offset lftrn
jmp trnarr
trnrgw: mov si,offset rgtrn
jmp trnarr
trnout endp
; move viewing window up (screen moves down).
; alternate entry upwin2 doesn't beep if invalid.
upwind proc near
mov ax,offset tlbuf ; place to put line temporarily
mov bx,offset twnd ; where to get lines from
call getcirc ; try to get a line
jnc upwin3 ; have a line, go show it
call outbel ; else ring bel
ret ; and return
upwin2: mov ax,offset tlbuf
mov bx,offset twnd
call getcirc
jnc upwin3
ret ; this just rets if no line avail.
upwin3: mov ax,offset blbuf ; place for bottom line
call getbot ; fetch bottom line
mov ax,offset blbuf
mov bx,offset bwnd
call putcirc ; save in circular buffer
mov ax,701h ; scroll down one line
xor cx,cx ; from top
mov dx,low_rgt ; to bottom
mov bh,curattr
int screen ; scroll it down
mov di,0 ; offset for destination
mov si,offset tlbuf ; where to get line from
mov cx,swidth ; length of line
push es
call scrseg
push ax
call scrwait
pop es
rep movsw ; copy the line in
pop es ; restore this
ret ; and return
upwind endp
; move viewing window down a line (screen scrolls up)
; entry dwin2 does same w/out checking to see if scroll is legal
dnwind proc near
mov ax,offset blbuf ; place to put line temporarily
mov bx,offset bwnd ; where to get lines from
call getcirc ; try to get a line
jnc dnwin3 ; have a line, go show it
call outbel ; else ring bel
ret ; and return
dnwin2: mov ax,offset blbuf
mov bx,offset bwnd
call getcirc
jnc dnwin3
ret ; this just rets if no line avail.
dnwin3: call scrprep ; save top line
mov ax,601h ; scroll up one line
xor cx,cx ; from top
mov dx,low_rgt ; to bottom
mov bh,curattr
int screen ; scroll it down
mov dx,low_rgt
mov dl,0 ; get addr of last line
call scrloc
mov di,ax ; this is offset in dest
mov si,offset blbuf ; where to get line from
mov cx,swidth ; length of line
push es
call scrseg
push ax
call scrwait
pop es
rep movsw ; copy the line in
pop es ; restore this
ret ; and return
dnwind endp
; move viewing window down as much as possible...
endwnd proc near
mov cx,1000 ; large number of lines
jmp dnwp1 ; and enter dwnpg
endwnd endp
; scroll viewing window down (contents move up) crt_lins times...
dnwpg proc near
mov cl,crt_lins
mov ch,0
dnwp1: push cx ; save this
call dnwin2
pop cx
loop dnwp1
ret ; and return
dnwpg endp
; home viewing window
homwnd proc near
mov cx,1000 ; large # of lines
jmp upwp1 ; join upwpg
homwnd endp
; scroll viewing window up (screen moves down) a page
upwpg proc near
mov cl,crt_lins
mov ch,0
upwp1: push cx
call upwin2
pop cx
loop upwp1
ret ; and return
upwpg endp
; get the bottom line into the buffer pointed to by ax.
getbot proc near
push ds
mov di,ax ; save dest
mov cx,swidth
mov dx,low_rgt
mov dl,0
call scrloc
mov si,ax
call scrseg
push ax
call scrwait
pop ds
rep movsw
pop ds
ret
getbot endp
; put a line into the circular buffer. Pass the buffer structure
; in bx, the pointer to the line in ax.
putcirc proc near
push si
push di
push cx
push dx
mov di,[bx].pp ; pick up buffer ptr
add di,2*swidth ; increment to next avail slot
cmp di,[bx].bend ; past end?
jb putci1 ; no, leave alone
mov di,[bx].orig ; else start at beginning
putci1: mov [bx].pp,di ; update ptr
mov si,ax ; this is source
mov cx,swidth
rep movsw ; copy into buffer
cmp [bx].lcnt,npgs*slen ; can we increment it?
jae putci2 ; no, keep going
inc [bx].lcnt ; else count this line
putci2: pop dx
pop cx
pop di
pop si ; restore registers
ret
putcirc endp
; get a line from the circular buffer, removing it from the buffer.
; returns with carry on if the buffer is empty.
; pass the buffer structure in bx, the buffer to copy the line into
; in ax.
getcirc proc near
push si
push di
push cx
push dx
cmp [bx].lcnt,0 ; any lines in buffer?
jne getci1 ; yes, ok to take one out.
stc ; else set carry
jmp short getcir3 ; and return
getci1: mov si,[bx].pp ; this is source
mov di,ax ; this is dest
mov cx,swidth ; # of chars to copy
rep movsw
mov si,[bx].pp ; get ptr again
sub si,2*swidth ; move back
cmp si,[bx].orig ; compare to origin
jae getcir2 ; still in range, continue
mov si,[bx].bend ; else use end of buffer
sub si,2*swidth-1 ; minus length of a piece
getcir2:mov [bx].pp,si ; update ptr
dec [bx].lcnt ; decrement # of lines in buffer
clc ; make sure no carry
getcir3:pop dx
pop cx
pop di
pop si
ret
getcirc endp
; call before scrolling to save top line...
scrprep proc near
push ds
mov si,0 ; offset of top line
mov cx,swidth ; length of line
mov di,offset tlbuf ; place to put line temporarily
call scrseg
push ax
call scrwait
pop ds
rep movsw ; copy the line
pop ds ; restore this
mov ax,offset tlbuf
mov bx,offset twnd ; this is where it goes
call putcirc ; put into buffer
ret ; and return
scrprep endp
; put the character in al to the screen
outtty proc near
test flags,capt ; capturing output?
jz outnoc ; no, forget this part
push ax ; save char
call captrtn ; give it captured character
pop ax ; restore character and keep going
outnoc: test flags1,prtscr ; should we be printing?
jz outnop ; no, keep going
push ax
mov ah,print_out
mov dl,al ; put character here for dos...
int dos
pop ax
outnop: test flags,emheath ; emulating heath?
jnz outnop1 ; yup, go do something smart
mov dl,al
mov ah,pbout
int dos ; else let dos print char
ret ; and return
outnop1:mov dx,cursor ; these may need cursor...
jmp ttstate ; jump according to current state
outtt0:
cmp al,32 ; special character?
jb outtt1 ; yes, handle specially...
cmp insmod,0 ; in insert mode?
je outnrm ; no, output normal
push ax ; save character
call inschr ; insert a character
pop ax
outnrm: xor bh,bh ; current page
mov cx,1 ; only one char
mov bl,curattr ; with current attribute
mov ah,9
int screen ; put onto screen
mov dx,cursor ; get cursor pos
currt: inc dl ; bump col
cmp dl,crt_cols ; see if in range
jb setcur ; in range, go set cursor
test flags1,lnwrap ; in wrap mode?
jz outign ; no, just return w/out updating cursor
wrap: xor dl,dl
inc dh ; handle wrap
setcur: cmp dh,crt_lins
jb setc1 ; not off end, keep going
push dx ; save row/col
call scrprep ; save top line in window buf
mov ax,0601h ; scroll up one line
xor cx,cx ; from 0,0
mov dx,low_rgt ; to 24,80
mov bh,7 ; nice attribute
int screen ; do the scroll
pop dx
mov dh,crt_lins ; go to bottom line again...
dec dh
setc1: xor bh,bh ; page is 0
mov cursor,dx ; save cursor pos
mov ah,2
int screen ; set cursor
outign: ret ; and return
; special character (in al)
outtt1: mov di,offset spctab ; special char table
mov cx,lspctab ; length of tbl
repne scasb ; look for char in tbl
jz outtt2 ; found, go do something with it
test flags,trnctl ; are we allowed to print carets?
jz outign ; no, just ignore it.
push ax ; save char
mov al,'^'
call outtty ; print caret
pop ax
add al,'A'-1 ; make printable
jmp outtty ; print, then return
outtt2: mov dx,cursor ; might need cursor pos
sub di,offset spctab+1 ; get index of char
shl di,1 ; double for word offset
jmp spcjmp[di] ; and go handle
; special char routines. cursor is in dx, char in al
outlf: inc dh ; bump row
jmp setcur
outcr: xor dl,dl ; set col to 0
jmp setcur
outbs: or dl,dl
jle setcur ; col 0, can't back up
dec dl ; back up col
jmp setcur ; and use if reasonable
outtab: mov dl,byte ptr cursor ; get initial column
add dl,8 ; tab is at most 8 columns
and dl,not 111b ; round down to a multiple of 8
cmp dl,crt_cols ; out of range?
jb setcur ; no, go set it
test flags1,lnwrap ; in wrap mode?
jnz outta1 ; yes, wrap to next line
mov dl,byte ptr low_rgt ; else just move to right margin
jmp setcur
outta1: jmp wrap
; stolen from bios
outbel: mov al,10110110b ; timer initialization
out timer+3,al
mov ax,beldiv ; bel divisor
out timer+2,al
mov al,ah
out timer+2,al ; output divisor
in al,bel_prt
mov ah,al ; remember original value
or al,3 ; turn speaker on
out bel_prt,al
mov cx,8888h
outbe1: loop outbe1 ; wait a while
mov al,ah
out bel_prt,al ; turn bell off
ret ; and return
outesc: mov ttstate,offset escseq ; expect escape sequence.
ret ; and return
; escape-char handling routines
escseq: mov ttstate,offset outtt0 ; put state back to normal
mov di,offset esctab ; escape char tbl
mov cx,lesctab ; length of tbl
repne scasb ; look for it in tbl
jz escsq1 ; found, go use it
jmp outtty ; not there, just print it
escsq1: sub di,offset esctab+1 ; get offset into tbl
shl di,1 ; convert to word offset
jmp escjmp[di] ; and go dispatch on it
; escape dispatch routines
revind: cmp dh,0
jle revin1
dec dh ; back up a row
jmp setcur ; and go set cursor
revin1: push dx ; save cursor pos
mov ax,701h ; scroll down one line
xor cx,cx ; from top
mov dx,low_rgt ; to bottom
mov bh,curattr
int screen ; scroll it down
pop dx ; restore cursor.
mov dh,0 ; set row back to 0
jmp setcur
curup: cmp dh,0 ; w/in range?
jle curu1 ; no, skip this
dec dh ; else back up
curu1: jmp setcur ; and go set position
curdwn: inc dh
jmp setcur ; increment row (setcur can scroll!)
; currt is above
clrscr: call curhom ; go home cursor
jmp clreow ; then clear to end of window
curhom: xor dx,dx ; move to 0,0
jmp setcur
clreow: cmp dl,0 ; at beginning of line?
jz clrw1 ; yes, skip this part...
push dx ; remember cursor pos
call clreol ; clear to end of this line
pop dx
inc dh ; bump row
xor dl,dl ; start from col 0
clrw1: cmp dh,crt_lins ; last line on screen
jnb clrw2 ; if not in range, forget it
mov ax,700h ; clear whole window
mov cx,dx ; this is beginning
mov dx,low_rgt
; mov dx,174fh ; this is lower right corner
mov bh,curattr ; default attribute
int screen ; go clear it
clrw2: ret ; and return
clreol: push es
mov cl,crt_cols ; last col + 1
sub cl,dl ; this is # of chars to move
xor ch,ch
jcxz clrl1
call scrloc ; compute screen location (to ax)
mov di,ax
call scrseg
mov es,ax ; address screen segment
call scrwait ; wait for retrace
mov ah,curattr ; current attribute
mov al,' ' ; fill char
rep stosw ; fill line with spaces
clrl1: pop es
ret ; and return
inslin: mov al,1 ; scroll one line
; alternate entry if inserting more then one line
inslin1:mov ch,dh ; start at current row
xor cl,cl ; column 0
mov dx,low_rgt
mov ah,7h ; scroll down.
mov bh,curattr ; attribute
cmp ch,dh ; moving last line down?
jne insli2 ; no, keep going
mov al,0 ; yes, just clear it
insli2: int screen
ret
dellin: mov al,1 ; scroll 1 line
; alternate entry if deleting more than one line
dellin1:mov ch,dh ; start at current row
xor cl,cl ; column 0
mov dx,low_rgt
; mov dx,174fh ; to bottom of screen
mov ah,6h ; scroll up.
mov bh,curattr ; attribute
cmp ch,dh ; deleting last line?
jne delli2 ; no, go on
mov al,0 ; yes, just blank it
delli2: int screen
ret
delchr: push ds
push es
pushf ; these may get changed...
mov cl,crt_cols
dec cl
sub cl,dl ; from what we're fiddling)
xor ch,ch
jcxz delch1 ; none to move, forget it
call scrloc ; compute location
mov di,ax
mov si,ax
add si,2 ; source is next position over
call scrseg ; pick up screen segment
push ax ; put screen segment onto stack
mov es,ax ; and in destination segment
call scrwait ; wait for retrace
pop ds ; address screen segment
rep movsw ; delete it
mov byte ptr [di],' ' ; kill char at end of line
delch1: popf
pop es
pop ds
ret
inschr: push ds
push es ; save these as well
pushf ; might as well save flags...
mov dx,cursor ; this is place to do it
mov cl,crt_cols
dec cl
; mov cl,79 ; this is last col to move, +1 for length
sub cl,dl ; compute distance to end
xor ch,ch ; clear top half of offset
jcxz insch1 ; nothing to move...
mov dl,crt_cols
sub dl,2 ; last col to move
; mov dl,78 ; this is address of last col to move
call scrloc ; compute pos
mov si,ax
mov di,ax
add di,2 ; destination is one byte over...
std ; remember to move us backwards
call scrseg ; find screen segment
mov es,ax
push ax ; save screen seg on stack
call scrwait ; wait until save to write
pop ds ; address screen segment
rep movsw ; move each char and attribute
insch1: popf
pop es
pop ds
ret ; and return
noins: mov insmod,0 ; turn off insert mode
ret ; and return
movcur: mov wcoord,2 ; want two coordinates...
mov ttstate,offset getcoord
ret ; and return
vtident: mov si,offset vtidstr
mov cx,lvtidst
vtid1: lodsb ; get a byte from the string
push si ; have to save from outprt
push cx
call outprt ; send to serial port
pop cx
pop si
loop vtid1 ; go thru all chars
ret ; and return
entins: mov insmod,0ffh ; enter insert mode...
ret ; and return
doansi: mov ansarg,0 ; ansi argument is 0 (default)
mov ttstate,offset getaarg ; state is get ansi argument
ret
getaarg:cmp al,'0'
jb getaa1 ; in range for digit?
cmp al,'9'
ja getaa1
sub al,'0' ; convert to binary
mov dl,al ; tuck away
mov al,ansarg
mov dh,10
mul dh ; shift sum
add al,dl ; add in this digit (what about ovfl?)
mov ansarg,al
ret ; and return
getaa1: cmp al,'?' ; the dreaded question mark?
jne getaa2
mov ttstate,offset ignn ; we ignore these...
mov igncnt,2 ; this is how many chars come after him
ret
getaa2: mov ttstate,offset outtt0 ; reset state
mov dx,cursor ; this needs cursor position
mov bl,ansarg
xchg al,bl ; put argument in nice place
cmp bl,'L' ; insert line?
jne getaa3
jmp inslin1 ; and go do it
getaa3: cmp bl,'M' ; maybe delete line?
jne getaa4
jmp dellin1
getaa4: ret ; ignore.
invvid: mov curattr,70h ; attribute for inverse video
ret
nrmvid: mov curattr,07h ; attribute for normal video
ret
dowrap: or flags1,lnwrap ; turn on wrap mode
ret ; and return
nowrap: and flags1,not lnwrap ; turn off wrap mode
ret ; and return
; get a coordinate.
getcoord:
sub al,32 ; coordinates offset by 32
mov si,wcoord
dec si
mov byte ptr coord[si],al ; fill in appropriate coordinate
mov wcoord,si ; update flag
jnz getco1 ; more needed, can't do anything yet
mov ttstate,offset outtt0 ; reset state
mov dx,coord ; get coordinates
jmp setcur ; and go jump there
getco1: ret
; ignore following igncnt characters
ignn: dec igncnt ; decrement count
jnz ignn1
mov ttstate,offset outtt0 ; put state back to normal if done
ignn1: ret
; save cursor
savecur:
mov oldcur,dx
ret
; restore cursor
restcur:
mov dx,oldcur
jmp setcur
outtty endp
; computes screen location to ax, given row and col in dx.
; trashes ax,bx
scrloc proc near
mov al,dh ; get row
mov bl,crt_cols ;** row size
mul bl ; multiply by row size
xor dh,dh ; clear col
add ax,dx ; this is current position
sal ax,1 ; double for attributes
ret
scrloc endp
; puts current screen segment in ax
scrseg proc near
mov ax,0b000h ; assume bw for now
cmp crt_mode,7 ; 7 is bw (***)
je scrse1
mov ax,0b800h ; color card
scrse1: ret
scrseg endp
; wait for retrace so can write to screen memory
scrwait proc near
cmp crt_mode,7 ; bw mode?
je scrwa3 ; yes, no waiting
push dx
mov dx,crt_status
scrwa1: in al,dx
test al,disp_enb ; display enable?
jnz scrwa1 ; yes, keep waiting
scrwa2: in al,dx
test al,disp_enb ; now wait for it to go off
jz scrwa2 ; so can have whole cycle
pop dx
scrwa3: ret ; that was easy...
scrwait endp
code ends
if1
%out [End of pass 1]
else
%out [End of assembly]
endif
end